import math
import sys
import random
import parse
import time
import os
import copy
from collections import deque


def reflex_play_single_ghost(problem, verbose):
    # Your p2 code here
    seed = problem['seed']
    if seed != -1:
        random.seed(seed, version=1)
    round = 0
    score = 0
    solution = 'seed: ' + str(seed) + '\n'
    winner = 'Ghost'
    queue = deque(['P'] + problem['ghostList'])

    while len(problem['pacmanLoc']) > 0 and len(problem['foodLoc']) > 0:
        if round == 0:
            solution = pack_solution(solution, round, problem['map'], '', '', '',
                                     problem['pacmanLoc'], problem['ghostLoc'], problem['foodLoc'])
        else:
            ch = queue.popleft()
            queue.append(ch)
            choose, score = move(ch, problem['map'], problem['pacmanLoc'],
                                 problem['ghostLoc'], problem['foodLoc'], score)
            solution = pack_solution(solution, round, problem['map'], ch, choose, score,
                                     problem['pacmanLoc'], problem['ghostLoc'], problem['foodLoc'])
        round += 1

    if len(problem['foodLoc']) == 0:
        winner = 'Pacman'

    solution += f"WIN: {winner}"

    return solution, winner


def pack_solution(solution, round, map, ch, dir, score, pacmanLoc, ghostLoc, foodLoc):
    tempMap = map
    if round == 0:
        solution += f"{round}\n"
    else:
        solution += f"{round}: {ch} moving {dir}\n"

    if len(pacmanLoc) > 0:
        tempMap[pacmanLoc[0]][pacmanLoc[1]] = 'P'

    if len(foodLoc) > 0:
        for food in foodLoc.keys():
            tempMap[food[0]][food[1]] = '.'

    if len(ghostLoc) > 0:
        for key in ghostLoc.keys():
            tempMap[ghostLoc[key][0]][ghostLoc[key][1]] = key

    for row in tempMap:
        solution += ''.join(row) + '\n'

    solution += f"score: {score}\n" if round != 0 else ""
    return solution


def get_better_direction(newLocDir, ghostLoc, foodLoc):
    dir = ''
    score = 0
    first = True
    for key in newLocDir.keys():
        position = newLocDir[key]
        minGhostDist = min([math.dist(x, position) for x in ghostLoc.values()])
        sortedFoodDist = sorted(
            [math.dist([x[0], x[1]], position) for x in foodLoc.keys()])
        if sortedFoodDist[0] == minGhostDist and len(sortedFoodDist) > 1:
            minFoodDist = sortedFoodDist[1]
        elif sortedFoodDist[0] == 0:
            minFoodDist = 1
        else:
            minFoodDist = sortedFoodDist[0]

        if minGhostDist <= 1:
            tempScore = minGhostDist * -50 + 1 / minFoodDist
        else:
            tempScore = minGhostDist + 1 / minFoodDist * 50

        if first:
            score = tempScore
            dir = key
            first = False
        else:
            if tempScore > score:
                score = tempScore
                dir = key

    return dir


def get_new_directions(ch, map, location, ghostLoc, foodLoc):
    availableDirs = []
    newLocDir = {}

    if ch == 'P':
        # check east
        if map[location[0]][location[1] + 1] != '%':
            availableDirs.append('E')
            newLocDir['E'] = [location[0], location[1] + 1]
        # check north
        if map[location[0] - 1][location[1]] != '%':
            availableDirs.append('N')
            newLocDir['N'] = [location[0] - 1, location[1]]
        # check south
        if map[location[0] + 1][location[1]] != '%':
            availableDirs.append('S')
            newLocDir['S'] = [location[0] + 1, location[1]]
        # check west
        if map[location[0]][location[1] - 1] != '%':
            availableDirs.append('W')
            newLocDir['W'] = [location[0], location[1] - 1]

        choose = get_better_direction(newLocDir, ghostLoc, foodLoc)
        newLoc = newLocDir[choose] if choose in newLocDir else location
    else:
        # check east
        if map[location[0]][location[1]+1] != '%' and \
                [location[0], location[1] + 1] not in ghostLoc.values():
            availableDirs.append('E')
            newLocDir['E'] = [location[0], location[1] + 1]
        # check north
        if map[location[0]-1][location[1]] != '%' and \
                [location[0] - 1, location[1]] not in ghostLoc.values():
            availableDirs.append('N')
            newLocDir['N'] = [location[0] - 1, location[1]]
        # check south
        if map[location[0]+1][location[1]] != '%' and \
                [location[0] + 1, location[1]] not in ghostLoc.values():
            availableDirs.append('S')
            newLocDir['S'] = [location[0] + 1, location[1]]
        # check west
        if map[location[0]][location[1]-1] != '%' and \
                [location[0], location[1] - 1] not in ghostLoc.values():
            availableDirs.append('W')
            newLocDir['W'] = [location[0], location[1] - 1]

        choose = random.choice(tuple(availableDirs))
        newLoc = newLocDir[choose]

    return choose, newLoc


def move(ch, map, pacmanLoc, ghostLoc, foodLoc, score):
    if ch == 'P':
        location = pacmanLoc
    else:
        location = ghostLoc[ch]
    choose, newLoc = get_new_directions(ch, map, location, ghostLoc, foodLoc)

    if ch == 'P':
        # check if pacman is moving to a ghost
        if [newLoc[0], newLoc[1]] in ghostLoc.values():
            pacmanLoc.clear()
            score -= 501
        # check if pacman is moving to a food
        elif (newLoc[0], newLoc[1]) in foodLoc:
            del foodLoc[(newLoc[0], newLoc[1])]
            pacmanLoc[0] = newLoc[0]
            pacmanLoc[1] = newLoc[1]
            score += 9
            if len(foodLoc) == 0:
                score += 500
        # check if pacman is moving to a space
        else:
            pacmanLoc[0] = newLoc[0]
            pacmanLoc[1] = newLoc[1]
            score -= 1
    else:
        # check if ghost is moving to pacman
        if newLoc[0] == pacmanLoc[0] and newLoc[1] == pacmanLoc[1]:
            pacmanLoc.clear()
            score -= 500
        ghostLoc[ch] = [newLoc[0], newLoc[1]]

    return choose, score


if __name__ == "__main__":
    # random.seed(0)
    test_case_id = int(sys.argv[1])
    problem_id = 2
    file_name_problem = str(test_case_id)+'.prob'
    file_name_sol = str(test_case_id)+'.sol'
    path = os.path.join('test_cases', 'p'+str(problem_id))
    problem = parse.read_layout_problem(os.path.join(path, file_name_problem))
    num_trials = int(sys.argv[2])
    verbose = bool(int(sys.argv[3]))
    print('test_case_id:', test_case_id)
    print('num_trials:', num_trials)
    print('verbose:', verbose)
    start = time.time()
    win_count = 0
    for i in range(num_trials):
        # print(i)
        solution, winner = reflex_play_single_ghost(
            copy.deepcopy(problem), verbose)
        if winner == 'Pacman':
            win_count += 1
        if verbose:
            print(solution)
    win_p = win_count/num_trials * 100
    end = time.time()
    print('time:', end - start)
    print('win %', win_p)
